package com.hp.springboot.utils;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;

/**
 * 异步处理
 *
 * @author hupan
 * @date 2021-08-06 11:02
 */
public class AsynExecutor {

    private static final ExecutorService ASYN_EXECUTOR;

    private static int rejectCount = 0;

    static {
        int cores = Runtime.getRuntime().availableProcessors();
        BasicThreadFactory factory = new BasicThreadFactory.Builder().namingPattern("asyn-schedule-pool-%d")
                                                                     .uncaughtExceptionHandler((t, e) -> {
                                                                         System.out.println(t.getName() + ":" + e.getMessage());
                                                                     })
                                                                     .daemon(true)
                                                                     .build();

        ASYN_EXECUTOR = new ScheduledThreadPoolExecutor(cores + 1, factory, (r, e) -> {
            rejectCount++;

            if (!e.isShutdown()) {
                r.run();
            }

        });
        monitor(ASYN_EXECUTOR);
    }

    public static void execute(Runnable thread) {
        ASYN_EXECUTOR.execute(thread);
    }

    public static Future<?> submit(Runnable thread) {
        return ASYN_EXECUTOR.submit(thread);
    }

    public static <T> Future<T> submit(Runnable thread, T result) {
        return ASYN_EXECUTOR.submit(thread, result);
    }

    public static <T> Future<T> submit(Callable<T> thread) {
        return ASYN_EXECUTOR.submit(thread);
    }

    public static void monitor(ExecutorService executor) {
        ScheduledThreadPoolExecutor pool = (ScheduledThreadPoolExecutor) executor;

        Map<String, String> map = new HashMap<>(16);
        map.put("activeCount", String.valueOf(pool.getActiveCount()));
        map.put("keepAliveTime", String.valueOf(pool.getKeepAliveTime(TimeUnit.SECONDS)));
        int coreSize = pool.getCorePoolSize();
        int maxSize = pool.getMaximumPoolSize();
        if (coreSize != 0) {
            map.put("active/core", String.valueOf((float) pool.getActiveCount() / (float) coreSize));
        }
        if (maxSize != 0) {
            map.put("active/max", String.valueOf((float) pool.getActiveCount() / (float) maxSize));
        }
        map.put("coreSize", String.valueOf(pool.getCorePoolSize()));
        map.put("maxSize", String.valueOf(pool.getMaximumPoolSize()));
        map.put("completedTaskCount", String.valueOf(pool.getCompletedTaskCount()));
        map.put("largestPoolSize", String.valueOf(pool.getLargestPoolSize()));
        map.put("taskCount", String.valueOf(pool.getTaskCount()));
        map.put("rejectCount", String.valueOf(rejectCount));
        map.put("queueSize", String.valueOf(pool.getQueue().size()));

        Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> System.out.println(map), 5, 10, TimeUnit.SECONDS);
    }

}
